#include "header.h"
#include "cmdline.h"


/*unsigned*/ char *msg;

unsigned char buf[LENGTH*RATE*SIZE*CHANNELS/8];

char *format; /* Audio input format */
char *_input_file; /* audio input file*/
unsigned char *htoname; /* remote host name */
u_short portnum; /* receiver port number */

int _nber_of_samples_send;
int _nber_sample_send_old;



double lost_rate;
int delay;
int max_delay; //maximum delay
int random_delay;//this variable is used to determine wheather the delay is random or not


/*This variable specifies the number of copie of the input file 
 *that we want to send, not usefull for /dev/dsp or /dev/audio 
 * */
int _nber_of_file_copie;


int sockfd, ok;
struct sockaddr_in *to;
struct hostent *toinfo;


void *thread_code_send(void *vargp);

int _cpt;

double avg_throughput;

main(int argc,char **argv)
{

  	int fd;	/* sound device file descriptor */
  	int arg;	/* argument for ioctl calls */
  	int status;   /* return status of system calls */
  	int flag = 0;
  	msg = (unsigned char*)malloc (sizeof(unsigned char)*TAILLE);
  	size_t addr_in_size;
 
  	u_long toaddr;
  
  /*********************** Statistical variables ******************************************/
  	double _random_value;
	double _nano_delay = 0;
	_nber_of_samples_send = 0;
	_nber_sample_send_old = 0;
	_cpt = 0;
	avg_throughput = 0;
  /************************ End of statistical variables declaration **********************/
   	lost_rate = 0;
	delay = 0;
	max_delay = 0; //maximum delay
	//permet de simuler la gigue
	random_delay = 0;
  
  
  	pthread_t thread_list;
  
  
  	//set to the default value
  	_nber_of_file_copie = NB_REPETITION; 
  
  	_input_file = (char*)malloc(sizeof(char)*MAX_INPUT_SIZE);
  	format = (char*)malloc(sizeof(char)*MAX_INPUT_SIZE);
  
  	//the default input file is /dev/audio
  	strncpy(_input_file,MU_LAW_FILE,strlen(MU_LAW_FILE));
  	strncpy(format,MU_LAW,strlen(MU_LAW));
  
  
  	portnum = SERV_PORT;
  	unsigned char *htoname = argv[1];
  //	printf("remote host name before : %s \n",htoname);
 
  	int check_in = 0;
  	//read arguments
  	parse_args(argc,argv,htoname,&portnum,_input_file,format,&check_in,&_nber_of_file_copie,&lost_rate,&max_delay,&random_delay);
  
  	//printf("rand  : %d % lf %d\n",random_delay,lost_rate,max_delay );
  
  	//msg = (char *)malloc(MSGSIZE);
  	to = (struct sockaddr_in *)malloc(sizeof(struct sockaddr_in));

  	if((toinfo = gethostbyname(htoname)) == NULL){
   		err_stop("Error : Unable to get host by name, exiting");
  	};
  	toaddr = *(u_long *)toinfo->h_addr_list[0];

  	addr_in_size = sizeof(struct sockaddr_in);
  	memset((char *)to,(char)0,addr_in_size);

  	to->sin_family = AF_INET;
  	to->sin_addr.s_addr = toaddr;
  	to->sin_port = /*(htons)*/portnum;

  	if((sockfd = socket (PF_INET, SOCK_DGRAM, 0)) == -1){
    	//fprintf(stderr,"Error %d in socket: %s\n",errno,sys_errlist[errno]);
    	exit(1);
  	};

  	printf("Audio input file : %s \n",_input_file);
  	
  	
  
  	//chek whether input file is not a system device  
  	if((strcmp(_input_file,MU_LAW_FILE) == 0) ||(strcmp(_input_file,PCM_FILE)==0 )){
  		flag = 1;
  	}
	  
  	if(((strcmp(format,PCM) == 0) && (check_in == -1))|| (strcmp(_input_file,PCM_FILE) == 0) ){
  		strcpy(_input_file,PCM_FILE);
  		//flag = 1;
  		//system(CAT_P);
  		fd = open_audio_device_MuLaw(_input_file,O_RDWR);
  	} 
  	else
  	if((strcmp(format,MU_LAW) == 0) && (check_in == -1)){
  		
  		flag = 1;
  		fd = open(_input_file,O_RDWR);
  	} 
  	else{
  		//printf("ICI test \n");
  		fd = open(_input_file, O_RDWR);
    	if (fd < 0) {
    		printf("open of %s failed",_input_file);
    		exit(1);
  		}
 	}
 
 	if(flag == 1){
 		arg = SIZE;	   // sample size 
  		status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
  		if (status == -1)
    		printf("SOUND_PCM_WRITE_BITS ioctl failed");
  		if (arg != SIZE)
    		printf("unable to set sample size");
  		arg = CHANNELS;  // mono or stereo 
  		status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
  		if (status == -1)
    		printf("SOUND_PCM_WRITE_CHANNELS ioctl failed");
  		if (arg != CHANNELS)
    		printf("unable to set number of channels");
  		arg = RATE;	   // sampling rate 
  		status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
  		if (status == -1)
    		printf("SOUND_PCM_WRITE_WRITE ioctl failed");
 		
 	}
 	struct timespec timeOut,remains;	
 	char *send_buff = (char*)malloc(sizeof(char)*15);
 	int nleft,nwritten;
 	
 	char*p = (char*)malloc (sizeof(char)*TAILLE*2);
 	
 	int n = 0;
 	int temps =0;
 	
 	pthread_create(&thread_list, NULL,thread_code_send,NULL);
 	
 	
 	while(n <_nber_of_file_copie){ 
  		while(read(fd,msg,TAILLE)){
  			
  			sprintf(send_buff,"%d", _nber_of_samples_send); 
 			
 			//printf("%d \n",_nber_of_samples_send);
 			
 			strcpy(p,send_buff);
 			p[strlen(send_buff)] = '$';
 			p[strlen(send_buff)+1] = '\0';
 			
 			//memcpy(p,&_nber_of_samples_send,sizeof(_nber_of_samples_send));
 			char *q = strcat(p,msg);
 			
  			timeOut.tv_sec = 0;
  			timeOut.tv_nsec = 20000000; // 20 milliseconds
  			nanosleep(&timeOut, &remains); 
  			
  			delayed(sockfd,q,addr_in_size);
  			
  			//if(sendto(sockfd,q,strlen(q),0,(struct sockaddr *)to,addr_in_size) == -1){
  			//if(sendto(sockfd,msg,TAILLE,0,(struct sockaddr *)to,addr_in_size) == -1){
			//	err_stop("Unnable to send data");
  			//}
  			_nber_of_samples_send++;
  		}
  		n++;
  		if(flag == 0 )
  		lseek (fd, 0, SEEK_SET);
 	}
 	//system("rm -f tmp");
 	
 	//dors pendant 2 secondes pour que l'autre thread finisse les statistiques
 	sleep(2);
 	
 	printf(" \n ");
	fprintf(stdout,"%s \n", "***************************Statistiques globales **************************");
 	printf(" Debit Moyen de transmission : %lf Kbps \n", (double)(avg_throughput/_cpt));
	printf(" Nombre d'echqntillons transmis : %d \n", _nber_of_samples_send);
 	//printf(" Nombre d'echantillont transmis");
}


void *thread_code_send(void *vargp)
{ 
	int debit = 0;
	//float taux_perte=0;
	
	char* format_string = "%15d %30d %40f\n";
	printf("\n");
	printf("*********************************************************\n");
	printf("*                                                       *\n");
	printf("*             Statistiques instantanees                 *\n");
	printf("*                                                       *\n");
	printf("* Le taux de perte calcule apres chaque seconde      *\n");
	printf("*********************************************************\n");
	
	printf("  \n");
	fprintf(stdout,"%8s %13s \n","Echantion envoyes","Debit Moyen envoie");
	
	//printf("Echantionn recus\t Debit Moyen reception \t Taux de pertes \n");
	
	while(1)
	{   
		//le thread va dormir une seconde et se reveille pour 
		//calculer les statistiques
		sleep (1);
		//compute the throughput in Kbps
		debit = ((_nber_of_samples_send - _nber_sample_send_old)*8*160)/1000;
		
		avg_throughput += debit; 
		_cpt++;
		_nber_sample_send_old = _nber_of_samples_send;
		fprintf(stdout,"%8d %15d Kbps \n",_nber_of_samples_send,debit);
		
	}
}

int delayed(int sockfd,char *q,size_t addr_in_size){
	double random_value;
	double nano_delay = 0;
	int second_delay;
	
	struct timespec _time_out,_remains;
	
	random_value = ((double)rand()) / RAND_MAX;
	//printf("%lf \n",random_value);
	
	
	if (random_value > lost_rate)
	{
		//deternining the delay of the paquet
		if (random_delay == -1)
		{
			nano_delay = (((double)rand()) / RAND_MAX) * max_delay;
		}
		else
		{
			nano_delay = max_delay;
		}		
		second_delay = (int)(nano_delay / 1000);
		nano_delay = (nano_delay - second_delay * 1000) * 1000000;
		_time_out.tv_sec = second_delay;
		_time_out.tv_nsec = nano_delay;
		nanosleep(&_time_out, &_remains);
		
		sendto(sockfd,q,strlen(q),0,(struct sockaddr *)to,addr_in_size);	
	}
}


